//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "ProposalICumulative.h"

Define_Module(ProposalICumulative);

void ProposalICumulative::initialize()
{
    numOfFrames = getAncestorPar("num_of_frames");
    ARQ_Block_Size = getAncestorPar("arq_block_size");//(bytes)
    PDU_Size = getAncestorPar("pdu_size");//(blocks)
    frameSize = getAncestorPar("data_size");
    blerstop = getAncestorPar("bstop");
    BLER = getAncestorPar("bstart");

    numOfBlocks = frameSize/ARQ_Block_Size;
    curBlock = 0;
    overhead = 0;
    statIndex = 0;

    for(int j=0; j<21 ; j++)
        statTable[j] = 0;
}

void ProposalICumulative::handleMessage(cMessage *msg)
{
    if(dynamic_cast<Data *>(msg))
        handleData(check_and_cast<Data *>(msg));

}

void ProposalICumulative::handleData(Data *msg)
{
    bool wereErrors = false;
    double prob;
    if(msg->getBLERup()==true)
    {
        statisticUpdate();
        if(BLER > blerstop)
            return;             //end of the simulation
    }
    curBlock = msg->getBSN();
    delete(msg);

    ARQ_pck *feedback = new ARQ_pck("ACK");
    feedback->setType(cumulativeACK);

    while( curBlock < numOfBlocks )
    {
        prob = uniform(0,100);
        if (prob < BLER)
        {
            wereErrors = true;
            EV<<"Error in block #"<<curBlock<<". ";
            overhead += 8 + conventionalOH; //16 CID + 1 LAST + 2 ACKtype + 11 BSN + 2 reserved for number of maps = 22 bits
            break;
        }
        else
            curBlock++;
    }
    if(!wereErrors)
        feedback->setLast(true);
    curBlock--;
    feedback->setBSN(curBlock);
    EV<<"Sending ACK for for the last received block #"<<curBlock<<endl;
    send(feedback,"toBase");
}

void ProposalICumulative::statisticUpdate()
{
    int temp = overhead/1024 + 0.5;           //overhead in KiloBits
    int type = getAncestorPar("simtype");
    statTable[statIndex++]= temp;
    overhead = 0;
    if(type==1)
    {
        BLER += 1;
        EV<<"BLER is up to ------------------------------> "<<BLER<<"%"<<endl;
    }
    else
    {
        if(ARQ_Block_Size==16)
            ARQ_Block_Size=64;
        else if(ARQ_Block_Size==64)
            ARQ_Block_Size=128;
        else if(ARQ_Block_Size==128)
            ARQ_Block_Size=256;
        else if(ARQ_Block_Size==256)
            ARQ_Block_Size=512;
        else if(ARQ_Block_Size==512)
            ARQ_Block_Size=1024;
        else
            BLER += 1;
    }
}

void ProposalICumulative::finish()
{
    blerstop -= 0.1;
    ostringstream oss;
    oss<<"Results ARQ"<<ARQ_Block_Size<<" Frame"<<frameSize<<".txt";
    string fname = oss.str();
    myfile.open (fname.c_str(),ios::app);
    myfile<<getClassName()<<" ARQ "<<ARQ_Block_Size<<endl;
    EV<<"---------------------------------------"<<endl;
    EV<<"Table of BLER to  Overhead in: "<<getClassName()<<endl;
    EV<<"Number of Frames: "<<numOfFrames<<" ; ARQ Block Size: "<<ARQ_Block_Size<<" B ; ";
    EV<<"PDU Size: "<<PDU_Size<<" blocks; Frame Size: "<<frameSize<<" B"<<endl;
    EV<<"---------------------------------------"<<endl;
    int type = getAncestorPar("simtype");
    if(type==1)
    {
        for(int j=0; j<statIndex ; j++)
        {
            myfile<<statTable[j]<<endl;
            EV<<statTable[j]<<endl;
        }
    }
    else
    {
        EV<<"BLER --> "<<blerstop<<"%"<<endl;
        EV<<"---------------------------------------"<<endl;
        EV<<statTable[0]<<endl;
        EV<<statTable[1]<<endl;
        EV<<statTable[2]<<endl;
        EV<<statTable[3]<<endl;
        EV<<statTable[4]<<endl;
        EV<<statTable[5]<<endl;
    }
    myfile.close();
    EV<<"---------------------------------------"<<endl;
}
